package com.rcloud.server.sealtalk.advice;

import com.rcloud.server.sealtalk.constant.ErrorCode;
import com.rcloud.server.sealtalk.exception.ServiceException;
import com.rcloud.server.sealtalk.interceptor.ServerApiParamHolder;
import com.rcloud.server.sealtalk.model.ServerApiParams;
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @Author: Jianlu.Yu
 * @Date: 2020/8/24
 * @Description: 全局打印 Controller 入参日志
 * @Copyright (c) 2020, rongcloud.cn All Rights Reserved
 */
@Aspect
@Component
public class LimitRequestAspect {

    private static ConcurrentHashMap<String, ExpiringMap<Integer, Integer>> interfaceMap = new ConcurrentHashMap<>();

    private Integer getCurrentUserId() {
        ServerApiParams serverApiParams = ServerApiParamHolder.get();
        if (serverApiParams != null) {
            return serverApiParams.getCurrentUserId();
        } else {
            return null;
        }
    }

    // 定义切点Pointcut
    @Pointcut("@annotation(limitRequest)")
    public void executeService(LimitRequest limitRequest) {
    }

    @Around("executeService(limitRequest)")
    public Object doAround(ProceedingJoinPoint pjp, LimitRequest limitRequest) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        ExpiringMap<Integer, Integer> expiringMap = interfaceMap.getOrDefault(request.getRequestURI(), ExpiringMap.builder().variableExpiration().build());
        if (Objects.isNull(getCurrentUserId())) {
            throw new ServiceException(ErrorCode.USER_NOT_EXIST);
        }

        Integer useCount = expiringMap.getOrDefault(getCurrentUserId(), 0);
        if (useCount > limitRequest.count()) {
            throw new ServiceException(ErrorCode.YUN_PIAN_SMS_ERROR);
        } else if (useCount == 0) {
            expiringMap.put(getCurrentUserId(), useCount + 1, ExpirationPolicy.CREATED, limitRequest.time(), TimeUnit.MILLISECONDS);
        } else {
            expiringMap.put(getCurrentUserId(), useCount + 1);
        }
        interfaceMap.put(request.getRequestURI(), expiringMap);
        return pjp.proceed();
    }
}
